﻿/*
    Copyright 2010, 2011 Eric Wong
	contact@optimalcycling.com
	http://www.optimalcycling.com
	Optimal Cycling - Advanced power pacing program for cyclists
	
	This file is part of Optimal Cycling.

    Optimal Cycling is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Optimal Cycling is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with Optimal Cycling.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.IO;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using System.Text;

namespace OptimalCycling.FileIO
{
    #region Alias

    using sizeT = System.UInt32;
    using size_array = System.UInt32;

    // Allow us to easily switch between floats and double values
#if REAL_IS_DOUBLE
    using real = System.Double;
    using real2 = Vector2d;
    using real4 = Vector4d;
    using real8 = Vector8d;
#else
    using real = System.Single;
    using real2 = Vector2;
    using real4 = Vector4;
    using real8 = Vector8;
#endif

    #endregion

    /// <summary>
    /// Functions used to serialize the program state to file and back in XML format.
    /// </summary>
    public static class XmlSerializeHelper
    {
        public static void ReadRealArray(XmlReader reader, out real[] arrayOfValues, string arrayName)
        {
            reader.ReadStartElement(arrayName);

            List<real> values = new List<real>();
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                values.Add(DataConversion.ConvertToReal(reader.ReadElementString(@"real")));
                reader.MoveToContent();
            }

            reader.ReadEndElement();

            arrayOfValues = values.ToArray();
        }

        public static void WriteRealArray(XmlWriter writer, real[] arrayOfValues, string arrayName)
        {
            writer.WriteStartElement(arrayName);

            foreach (real value in arrayOfValues)
            {
                writer.WriteElementString(@"real", ((double)value).ToString());
            }

            writer.WriteEndElement();
        }

        public static void ReadReal4Array(XmlReader reader, out real4[] arrayOfValues, string arrayName)
        {
            reader.ReadStartElement(arrayName);

            List<real4> values = new List<real4>();
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                reader.ReadStartElement(@"real4");

                real4 readValue = new real4();
                readValue.X = DataConversion.ConvertToReal(reader.ReadElementString(@"s0"));
                readValue.Y = DataConversion.ConvertToReal(reader.ReadElementString(@"s1"));
                readValue.Z = DataConversion.ConvertToReal(reader.ReadElementString(@"s2"));
                readValue.W = DataConversion.ConvertToReal(reader.ReadElementString(@"s3"));
                values.Add(readValue);

                reader.ReadEndElement();
                reader.MoveToContent();
            }

            reader.ReadEndElement();

            arrayOfValues = values.ToArray();
        }

        public static void WriteReal4Array(XmlWriter writer, real4[] arrayOfValues, string arrayName)
        {
            writer.WriteStartElement(arrayName);

            foreach (real4 value in arrayOfValues)
            {
                writer.WriteStartElement(@"real4");
                writer.WriteElementString(@"s0", ((double)value.X).ToString());
                writer.WriteElementString(@"s1", ((double)value.Y).ToString());
                writer.WriteElementString(@"s2", ((double)value.Z).ToString());
                writer.WriteElementString(@"s3", ((double)value.W).ToString());
                writer.WriteEndElement();
            }

            writer.WriteEndElement();
        }

        public static void ReadReal8Array(XmlReader reader, out real8[] arrayOfValues, string arrayName)
        {
            reader.ReadStartElement(arrayName);

            List<real8> values = new List<real8>();
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                reader.ReadStartElement(@"real8");

                real8 readValue = new real8();
                readValue.s0 = DataConversion.ConvertToReal(reader.ReadElementString(@"s0"));
                readValue.s1 = DataConversion.ConvertToReal(reader.ReadElementString(@"s1"));
                readValue.s2 = DataConversion.ConvertToReal(reader.ReadElementString(@"s2"));
                readValue.s3 = DataConversion.ConvertToReal(reader.ReadElementString(@"s3"));
                readValue.s4 = DataConversion.ConvertToReal(reader.ReadElementString(@"s4"));
                readValue.s5 = DataConversion.ConvertToReal(reader.ReadElementString(@"s5"));
                readValue.s6 = DataConversion.ConvertToReal(reader.ReadElementString(@"s6"));
                readValue.s7 = DataConversion.ConvertToReal(reader.ReadElementString(@"s7"));
                values.Add(readValue);

                reader.ReadEndElement();
                reader.MoveToContent();
            }

            reader.ReadEndElement();

            arrayOfValues = values.ToArray();
        }

        public static void WriteReal8Array(XmlWriter writer, real8[] arrayOfValues, string arrayName)
        {
            writer.WriteStartElement(arrayName);

            foreach (real8 value in arrayOfValues)
            {
                writer.WriteStartElement(@"real8");
                writer.WriteElementString(@"s0", ((double)value.s0).ToString());
                writer.WriteElementString(@"s1", ((double)value.s1).ToString());
                writer.WriteElementString(@"s2", ((double)value.s2).ToString());
                writer.WriteElementString(@"s3", ((double)value.s3).ToString());
                writer.WriteElementString(@"s4", ((double)value.s3).ToString());
                writer.WriteElementString(@"s5", ((double)value.s3).ToString());
                writer.WriteElementString(@"s6", ((double)value.s3).ToString());
                writer.WriteElementString(@"s7", ((double)value.s3).ToString());
                writer.WriteEndElement();
            }

            writer.WriteEndElement();
        }

        public static void ReadUInt4Array(XmlReader reader, out uint4[] arrayOfValues, string arrayName)
        {
            reader.ReadStartElement(arrayName);

            List<uint4> values = new List<uint4>();
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                reader.ReadStartElement(@"uint4");

                uint4 readValue = new uint4();
                readValue.X = Convert.ToUInt32(reader.ReadElementString(@"s0"));
                readValue.Y = Convert.ToUInt32(reader.ReadElementString(@"s1"));
                readValue.Z = Convert.ToUInt32(reader.ReadElementString(@"s2"));
                readValue.W = Convert.ToUInt32(reader.ReadElementString(@"s3"));
                values.Add(readValue);

                reader.ReadEndElement();
                reader.MoveToContent();
            }

            reader.ReadEndElement();

            arrayOfValues = values.ToArray();
        }

        public static void WriteUInt4Array(XmlWriter writer, uint4[] arrayOfValues, string arrayName)
        {
            writer.WriteStartElement(arrayName);

            foreach (uint4 value in arrayOfValues)
            {
                writer.WriteStartElement(@"uint4");
                writer.WriteElementString(@"s0", (value.X).ToString());
                writer.WriteElementString(@"s1", (value.Y).ToString());
                writer.WriteElementString(@"s2", (value.Z).ToString());
                writer.WriteElementString(@"s3", (value.W).ToString());
                writer.WriteEndElement();
            }
 
            writer.WriteEndElement();
        }

        public static void ReadIntArray(XmlReader reader, out int[] arrayOfValues, string arrayName)
        {
            reader.ReadStartElement(arrayName);

            List<int> values = new List<int>();
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                values.Add(Convert.ToInt32(reader.ReadElementString(@"int")));
                reader.MoveToContent();
            }

            reader.ReadEndElement();

            arrayOfValues = values.ToArray();
        }

        public static void WriteIntArray(XmlWriter writer, int[] arrayOfValues, string arrayName)
        {
            writer.WriteStartElement(arrayName);

            foreach (int value in arrayOfValues)
            {
                writer.WriteElementString(@"int", value.ToString());
            }

            writer.WriteEndElement();
        }

        public static void ReadsizeTArray(XmlReader reader, out sizeT[] arrayOfValues, string arrayName)
        {
            reader.ReadStartElement(arrayName);

            List<sizeT> values = new List<sizeT>();
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                values.Add(DataConversion.ConvertTosizeT(reader.ReadElementString(@"sizeT")));
                reader.MoveToContent();
            }

            reader.ReadEndElement();

            arrayOfValues = values.ToArray();
        }

        public static void WritesizeTArray(XmlWriter writer, sizeT[] arrayOfValues, string arrayName)
        {
            writer.WriteStartElement(arrayName);

            foreach (sizeT value in arrayOfValues)
            {
                writer.WriteElementString(@"sizeT", value.ToString());
            }

            writer.WriteEndElement();
        }

        public static void ReadRealValue(XmlReader reader, out real value, string arrayName)
        {
            reader.ReadStartElement(arrayName);
            value = DataConversion.ConvertToReal(reader.ReadElementString(@"real"));
            reader.MoveToContent();
            reader.ReadEndElement();
        }

        public static void WriteRealValue(XmlWriter writer, real value, string arrayName)
        {
            writer.WriteStartElement(arrayName);
            writer.WriteElementString(@"real", value.ToString());
            writer.WriteEndElement();
        }

        public static void ReadULongValue(XmlReader reader, out ulong value, string arrayName)
        {
            reader.ReadStartElement(arrayName);
            value = Convert.ToUInt64(reader.ReadElementString(@"ulong"));
            reader.MoveToContent();
            reader.ReadEndElement();
        }

        public static void WriteULongValue(XmlWriter writer, ulong value, string arrayName)
        {
            writer.WriteStartElement(arrayName);
            writer.WriteElementString(@"ulong", value.ToString());
            writer.WriteEndElement();
        }
    }
}
